package com.opNaga.bpmp.flowObject.event;

import com.opNaga.bpmp.BPMPElement;
import com.opNaga.bpmp.connectingObject.messageFlow.MessageFlow;
import com.opNaga.bpmp.connectingObject.messageFlow.MessageFlowSource;
import com.opNaga.bpmp.connectingObject.messageFlow.MessageFlowTarget;
import com.opNaga.bpmp.connectingObject.sequenceFlow.SequenceFlow;
import com.opNaga.bpmp.connectingObject.sequenceFlow.SequenceFlowSource;
import com.opNaga.bpmp.connectingObject.sequenceFlow.SequenceFlowTarget;
import com.opNaga.bpmp.flowObject.activity.Portal;
import com.opNaga.bpmp.flowObject.activity.PortalEntry;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * User: Junyi BEI
 * Date: 19/01/2012
 * Time: 13:57
 */
public class IntermediateEvent extends Event implements SequenceFlowSource, SequenceFlowTarget, MessageFlowTarget, Portal {
  private Set<BPMPElement> outwardSequenceFlow = new HashSet<BPMPElement>();
  private Set<BPMPElement> inwardSequenceFlow = new HashSet<BPMPElement>();
  private Set<BPMPElement> inwardMessageFlow = new HashSet<BPMPElement>();
  private BPMPElement entry;

  public IntermediateEvent() {
    super();
  }
  
  public IntermediateEvent(String t) {
    super(t);
  }

  @Override
  public String getType() {
    return "Intermediate Event";
  }

  @Override
  public boolean destroy() {
    Iterator<BPMPElement> osfIt = iterateOutwardSequenceFlows();
    while(osfIt.hasNext()) {
      BPMPElement be = osfIt.next();
      if(!be.destroy()) {
        return standardMessage(800, be);
      }
    }
    Iterator<BPMPElement> isfIt = iterateInwardSequenceFlows();
    while(isfIt.hasNext()) {
      BPMPElement be = isfIt.next();
      if(!be.destroy()) {
        return standardMessage(801, be);
      }
    }
    Iterator<BPMPElement> imfIt = iterateInwardMessageFlows();
    while(imfIt.hasNext()) {
      BPMPElement be = imfIt.next();
      if(!be.destroy()) {
        return standardMessage(801, be);
      }
    }
    return super.destroy();
  }

  public boolean addInwardMessageFlow(BPMPElement be) {
    if(!(be instanceof MessageFlow)) {
      return standardMessage(140, be);
    }
    if(!inwardMessageFlow.add(be)) {
      return standardMessage(141, be);
    }
    return standardMessage(194, be);
  }

  public boolean removeInwardMessageFlow(BPMPElement be) {
    if(!(be instanceof MessageFlow)) {
      return standardMessage(240, be);
    }
    if(!inwardMessageFlow.remove(be)) {
      return standardMessage(241, be);
    }
    return standardMessage(294, be);
  }

  public boolean isInwardMessageFlowEmpty() {
    return inwardMessageFlow.isEmpty();
  }

  public int inwardMessageFlowSize() {
    return inwardSequenceFlow.size();
  }

  public Iterator<BPMPElement> iterateInwardMessageFlows() {
    return new ArrayList<BPMPElement>(inwardMessageFlow).iterator();
  }

  public boolean addOutwardSequenceFlow(BPMPElement be) {
    if(!(be instanceof SequenceFlow)) {
      return standardMessage(100, be);
    }
    if(!outwardSequenceFlow.add(be)) {
      return standardMessage(101, be);
    }
    return standardMessage(190, be);
  }

  public boolean removeOutwardSequenceFlow(BPMPElement be) {
    if(!(be instanceof SequenceFlow)) {
      return standardMessage(200, be);
    }
    if(!outwardSequenceFlow.remove(be)) {
      return standardMessage(201, be);
    }
    return standardMessage(290, be);
  }

  public boolean isOutwardSequenceFlowEmpty() {
    return outwardSequenceFlow.isEmpty();
  }

  public int outwardSequenceFlowSize() {
    return outwardSequenceFlow.size();
  }

  public Iterator<BPMPElement> iterateOutwardSequenceFlows() {
    return new ArrayList <BPMPElement>(outwardSequenceFlow).iterator();
  }

  public boolean addInwardSequenceFlow(BPMPElement be) {
    if(!(be instanceof SequenceFlow)) {
      return standardMessage(130, be);
    }
    if(!inwardSequenceFlow.add(be)) {
      return standardMessage(131, be);
    }
    return standardMessage(193, be);
  }

  public boolean removeInwardSequenceFlow(BPMPElement be) {
    if(!(be instanceof SequenceFlow)) {
      return standardMessage(230, be);
    }
    if(!inwardSequenceFlow.remove(be)) {
      return standardMessage(231, be);
    }
    return standardMessage(293, be);
  }

  public boolean isInwardSequenceFlowEmpty() {
    return inwardSequenceFlow.isEmpty();
  }

  public int inwardSequenceFlowSize() {
    return inwardSequenceFlow.size();
  }

  public Iterator<BPMPElement> iterateInwardSequenceFlows() {
    return new ArrayList <BPMPElement>(inwardSequenceFlow).iterator();
  }

  public boolean setEntry(BPMPElement be) {
    if(!PortalEntry.class.isAssignableFrom(be.getClass())) {
      return standardMessage(620, be);
    }
    if(entry != null) {
      return standardMessage(621, be);
    }
    entry = be;
    return standardMessage(642, be);
  }

  public BPMPElement getEntry() {
    return entry;
  }

  public BPMPElement linkTo(BPMPElement be) {
    if(SequenceFlowTarget.class.isAssignableFrom(be.getClass()) && ((SequenceFlowTarget) be).getRoot() == root) {
      BPMPElement sf;
      if(manager != null) {
        if(be.getManager() == manager) {
          sf = manager.createInstance("sf", "-s=" + name, "-t=" + be.getName());
          if(sf != null) {
            standardMessage(910, be, sf);
            return sf;
          } else {
            standardMessage(903, be);
            return null;
          }
        } else {
          standardMessage(902, be);
          return null;
        }
      } else {
        sf = new SequenceFlow();
        if(!((SequenceFlow) sf).setTarget(be)) {
          sf.destroy();
          standardMessage(900, be, sf);
          return null;
        }
        if(!((SequenceFlow) sf).setSource(this)) {
          sf.destroy();
          standardMessage(901, be, sf);
          return null;
        }
        if(standardMessage(911, be, sf)) {
          return sf;
        }
      }
    }
    return super.linkTo(be);
  }

  public BPMPElement getLinkTo(BPMPElement be) {
    if(SequenceFlowTarget.class.isAssignableFrom(be.getClass()) && ((SequenceFlowTarget) be).getRoot() == root) {
      Iterator<BPMPElement> osfIt = iterateOutwardSequenceFlows();
      while(osfIt.hasNext()) {
        BPMPElement osf = osfIt.next();
        if(((SequenceFlow) osf).getTarget() == be) {
          standardMessage(950, be, osf);
          return osf;
        }
      }
      standardMessage(940, be);
      return null;
    }
    return super.getLinkTo(be);
  }

  public BPMPElement linkFrom(BPMPElement be) {
    if(SequenceFlowSource.class.isAssignableFrom(be.getClass()) && ((SequenceFlowSource) be).getRoot() == root) {
      BPMPElement sf;
      if(manager != null) {
        if(be.getManager() == manager) {
          sf = manager.createInstance("sf", "-s=" + be.getName(), "-t=" + name);
          if(sf != null) {
            standardMessage(930, be, sf);
            return sf;
          } else {
            standardMessage(923, be);
            return null;
          }
        } else {
          standardMessage(922, be);
          return null;
        }
      } else {
        sf = new SequenceFlow();
        if(!((SequenceFlow) sf).setTarget(this)) {
          sf.destroy();
          standardMessage(920, be, sf);
          return null;
        }
        if(!((SequenceFlow) sf).setSource(be)) {
          sf.destroy();
          standardMessage(921, be, sf);
          return null;
        }
        if(standardMessage(931, be, sf)) {
          return sf;
        }
      }
    }
    if(MessageFlowSource.class.isAssignableFrom(be.getClass()) && ((MessageFlowSource) be).getRoot() != root) {
      BPMPElement mf;
      if(manager != null) {
        if(be.getManager() == manager) {
          mf = manager.createInstance("mf", "-s=" + be.getName(), "-t=" + name);
          if(mf != null) {
            standardMessage(930, be, mf);
            return mf;
          } else {
            standardMessage(923, be);
            return null;
          }
        } else {
          standardMessage(922, be);
          return null;
        }
      } else {
        mf = new MessageFlow();
        if(!((MessageFlow) mf).setTarget(this)) {
          mf.destroy();
          standardMessage(920, be, mf);
          return null;
        }
        if(!((MessageFlow) mf).setSource(be)) {
          mf.destroy();
          standardMessage(921, be, mf);
          return null;
        }
        if(standardMessage(931, be, mf)) {
          return mf;
        }
      }
    }
    return super.linkFrom(this);
  }

  public BPMPElement getLinkFrom(BPMPElement be) {
    if(SequenceFlowSource.class.isAssignableFrom(be.getClass()) && ((SequenceFlowSource) be).getRoot() == root) {
      Iterator<BPMPElement> isfIt = iterateInwardSequenceFlows();
      while(isfIt.hasNext()) {
        BPMPElement isf = isfIt.next();
        if(((SequenceFlow) isf).getSource() == be) {
          if(standardMessage(970, be, isf)) {
            return isf;
          } else {
            return null;
          }
        }
      }
      standardMessage(960, be);
      return null;
    }
    if(MessageFlowSource.class.isAssignableFrom(be.getClass()) && ((MessageFlowSource) be).getRoot() != root) {
      Iterator<BPMPElement> imfIt = iterateInwardMessageFlows();
      while(imfIt.hasNext()) {
        BPMPElement imf = imfIt.next();
        if(((MessageFlow) imf).getSource() == be) {
          if(standardMessage(970, be, imf)) {
            return imf;
          } else {
            return null;
          }
        }
      }
      standardMessage(960, be);
      return null;
    }
    return super.getLinkFrom(be);
  }
}
